using ASPApiDemo.Common.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace ASPApiDemo.Common.Option;

public static class ConfigurableOptions
{
    // 全局的Configuration对象，用于获取配置信息
    // 这种写法需要在Program.cs中进行配置builder.configuration.ConfigureApplication();
    // 后续我们将定义一个静态AppService类统一管理这些全局属性，在program.cs中调用的AppService类中的初始化方法
    // internal static IConfiguration Configuration;
    // public static void ConfigureApplication(this IConfiguration configuration)
    // {
    //     Configuration = configuration;
    // }
    //【1】泛型版本：适用于编译时已知类型的情况
    public static IServiceCollection AddConfigurableOptions<TOptions>(this IServiceCollection services)
        where TOptions : class, IConfigurableOptions
    {
        Type optionsType = typeof(TOptions);
        //将类名映射到json文件中的配置名
        string path = GetConfigurationPath(optionsType);
        services.Configure<TOptions>(AppService.Configuration.GetSection(path));
        // services.Configure<TOptions>(Configuration.GetSection(path));
        return services;
    }
    //【2】非泛型版本：使用反射，适用于运行时动态确定类型的情况
    // 可以在运行时动态处理任何类型的选项类，而不需要在编译时就确定具体类型
    // 非常适合需要动态加载或处理多种配置类型的场景。
    public static IServiceCollection AddConfigurableOptions(this IServiceCollection services, Type type)
    {
        string path = GetConfigurationPath(type);
        var config = AppService.Configuration.GetSection(path);
        // 声明四个泛型类型的变量，这些都是ASP.NET Core选项模式中的核心类型
        Type iOptionsChangeTokenSource = typeof(IOptionsChangeTokenSource<>);
        Type iConfigureOptions = typeof(IConfigureOptions<>);
        Type configurationChangeTokenSource = typeof(ConfigurationChangeTokenSource<>);
        Type namedConfigureFromConfigurationOptions = typeof(NamedConfigureFromConfigurationOptions<>);
        iOptionsChangeTokenSource = iOptionsChangeTokenSource.MakeGenericType(type);
        iConfigureOptions = iConfigureOptions.MakeGenericType(type);
        configurationChangeTokenSource = configurationChangeTokenSource.MakeGenericType(type);
        namedConfigureFromConfigurationOptions = namedConfigureFromConfigurationOptions.MakeGenericType(type);
        // 添加Options框架的基础服务
        services.AddOptions();
        // 注册IOptionsChangeTokenSource<T>服务实例
        // 这个服务负责在配置发生变化时通知选项系统
        // Activator.CreateInstance动态创建ConfigurationChangeTokenSource<T>的实例
        // Options.DefaultName是一个常量，表示默认的选项名称（通常是空字符串）
        services.AddSingleton(iOptionsChangeTokenSource,
            Activator.CreateInstance(configurationChangeTokenSource, Options.DefaultName, config) ??
            throw new InvalidOperationException());
        // 注册IConfigureOptions<T>服务实例
        // 这个服务负责将配置值绑定到选项类型的实例上
        // 同样使用Activator.CreateInstance动态创建NamedConfigureFromConfigurationOptions<T>的实例
        return services.AddSingleton(iConfigureOptions,
            Activator.CreateInstance(namedConfigureFromConfigurationOptions, Options.DefaultName, config) ??
            throw new InvalidOperationException());
    }

    //从Type中动态获取配置路径，自动去掉常见的"Option"或"Options"后缀
    public static string GetConfigurationPath(Type optionsType)
    {
        var endPath = new[] { "Option", "Options" };
        var configurationPath = optionsType.Name;
        foreach (var s in endPath)
        {
            if (configurationPath.EndsWith(s))
            {
                //从字符串末尾向前偏移 s.Length 个字符
                //等同于configurationPath.Remove(configurationPath.Length - s.Length);
                return configurationPath[..^s.Length];
            }
        }

        return configurationPath;
    }
}